package database

import (
	"context"
	"database/sql"
	"fmt"
	"saasems/models"
	"time"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

type AlertHistory struct {
	TenantID    string           `gorm:"column:tenant_id"`
	DeviceID    string           `gorm:"column:device_id"`
	MetricName  string           `gorm:"column:metric_name"`
	MetricValue float64          `gorm:"column:metric_value"`
	Rule        models.AlertRule `gorm:"column:rule;type:jsonb"`
	TriggeredAt time.Time        `gorm:"column:triggered_at"`
}

func (db *PostgresDB) SaveAlert(alert AlertHistory) error {
	return db.db.Create(&alert).Error
}

func (db *PostgresDB) Close() error {
	sqlDB, err := db.db.DB()
	if err != nil {
		return err
	}
	return sqlDB.Close()
}

type PostgresDB struct {
	db *gorm.DB
}

func (p *PostgresDB) GetDB() *gorm.DB {
	return p.db
}

func NewPostgresDB(connStr string) (*PostgresDB, error) {
	db, err := gorm.Open(postgres.Open(connStr), &gorm.Config{})
	if err != nil {
		return nil, fmt.Errorf("数据库连接失败: %w", err)
	}
	return &PostgresDB{db: db}, nil
}

func (p *PostgresDB) Rollback(tx *TxWrapper) error {
	return tx.Rollback().Error
}

func (p *PostgresDB) Commit(tx *TxWrapper) error {
	return tx.Commit().Error
}

type TxWrapper struct {
	*gorm.DB
}

func (tx *TxWrapper) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
	return tx.DB.WithContext(ctx).Raw(query, args...).Scan(dest).Error
}

func (tx *TxWrapper) NamedExecContext(ctx context.Context, query string, arg interface{}) error {
	return tx.DB.WithContext(ctx).Exec(query, arg).Error
}

func (p *PostgresDB) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*TxWrapper, error) {
	tx := p.db.Begin(opts)
	if tx.Error != nil {
		return nil, tx.Error
	}
	return &TxWrapper{tx}, nil
}

func (p *PostgresDB) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
	return p.db.WithContext(ctx).Raw(query, args...).Scan(dest).Error
}

func (p *PostgresDB) NamedExecContext(ctx context.Context, query string, arg interface{}) error {
	return p.db.WithContext(ctx).Exec(query, arg).Error
}
